home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / dviware / dvi2qms / qmsfonts.c < prev    next >
C/C++ Source or Header  |  1990-10-01  |  17KB  |  615 lines

  1. /* qmsfonts.c: font module for dvi printing on qms printers
  2.  * Copyright 1985 Massachusetts Institute of Technology
  3.  * Some portions were written by Scott Simpson, TRW
  4.  */
  5.  
  6. #include <stdio.h>
  7. #include <sys/types.h>
  8. #include <sys/dir.h>
  9. #include "util.h"
  10. #include "fonts.h"
  11. #include "findfile.h"
  12.  
  13. #define MAXDVIFONTS  256    /* Maximum number of DVI fonts allowed */
  14. #define MAXQMSFONTS  256    /* Maximum number of QMS fonts allowed */
  15. #define QMSMAXBLOCKS 386    /* Stated on qms status page */
  16. #define MAXCHARS     128    /* Max chars per QMS font */
  17. #define MAXFNTDIR     16    /* Max number of dirs to look for fonts */
  18. #define MAXFNTNAMLEN  32    /* Maximum number of chars in a font name */
  19. #define USEROTPXL      1    /* Write and read rotated pxl files */
  20.  
  21. #define DELETEFONT "^DF%05.5d%c^G"
  22. #define DEFINEFONT "^(^DF%05.5d%c%c%4.4s%03.3dT"
  23. #define ADDTOFONT  "^(^DFI%05.5d%c%c%4.4s%03.3dT"
  24. #define DEFINECHAR ",%c%c%03.3d%03.3d%03.3d%c%03.3d%c%03.3d"
  25. #define ENDDEF     "^G^)"
  26. #define SELECTFONT "^IS%05.5d"
  27.  
  28. unsigned char *malloc();
  29. char *strcat();
  30. char *strcpy();
  31. char *strncpy();
  32. char *strncmp();
  33. char *strcmp();
  34.  
  35. long numerator,denominator,half_denominator,jobmag;
  36. char job_orientation,printer_orientation;
  37.  
  38. int      freeblocks = QMSMAXBLOCKS;   /* free space on printer */
  39. char     *hex = "0123456789ABCDEF";   
  40. FILE     *qms;                        /* output device */
  41. char *filter_name;                    /* the name of the calling prog */
  42. char *fntdirvec[MAXFNTDIR];
  43. int fntdirveclen;
  44.  
  45. #define QC_LOADED    0x0001    /* Char has been loaded in the printer */
  46. #define QC_NOGLYPH   0x0002    /* Glyph is still in pxl file */
  47. #define QC_ROTATED   0x0004    /* Glyph has been rotated */
  48. #define QC_NEEDED    0x0008    /* This char is needed on this page */
  49.  
  50. struct qmschar {
  51.   short qc_info,qc_qmswidth;
  52.   short qc_height,qc_width;
  53.   short qc_xoffset,qc_yoffset;
  54.   long  qc_texwidth,qc_pxlwidth;
  55.   union {long l; unsigned char *p} qc_glyph;
  56. };
  57.  
  58. #define QF_LOADED    0x0001    /* Font has been loaded into printer */
  59. #define QF_RELOAD    0x0002    /* We have to load more needed chars */
  60. #define QF_FILE      0x0004    /* Font hasn't been loaded from the file */
  61.  
  62. struct qmsfont {
  63.   short          qf_info;
  64.   short          qf_qmsnumber;
  65.   short          qf_maxheight;
  66.   long           qf_mag;
  67.   long           qf_words_used;
  68.   long           qf_words_needed;
  69.   long           qf_timestamp;
  70.   char           qf_qmsname[4];
  71.   long           qf_pxl_checksum;
  72.   long           qf_pxl_mag_val;
  73.   long           qf_pxl_design_size;
  74.   long           qf_s;
  75.   char           qf_name[MAXFNTNAMLEN];
  76.   char           qf_filename[MAXNAMLEN];
  77.   struct qmschar qf_char[MAXCHARS]; 
  78. } *qmsfonts[MAXQMSFONTS];
  79.  
  80. int nqmsfonts;
  81. struct qmsfont *curfnt; /* ptr to current and last font */
  82. long timestamp;            /* Timestamp for stamping qms fonts */
  83.  
  84. /* The dvifont struct provides a (possible) many-to-one mapping
  85.  * because several DVI fonts can map to the same QMS font during font
  86.  * substitution.
  87.  */
  88. struct dvifont {
  89.   unsigned long   df_num;    /* DVI font number */
  90.   struct qmsfont  *df_qmsfont;    /* Font which contains */
  91. } dvifonts[MAXDVIFONTS];
  92. int ndvifonts;
  93.  
  94. long max(a,b)
  95.      long a,b;
  96. {
  97.   return((a>b)? a:b);
  98. }
  99.  
  100. long min(a,b)
  101.      long a,b;
  102. {
  103.   return((a<b)? a:b);
  104. }
  105.  
  106. /* called at the beginning of the driver program */
  107. f_init(printer,pgmnam,dirvec,dirveclen,num,den,mag,options)
  108. FILE *printer;
  109. char *pgmnam,*dirvec[];
  110. int dirveclen;
  111. long num,den,mag;
  112. unsigned long options;
  113. {
  114.   int i;
  115.   
  116.   numerator = num;
  117.   denominator = den;
  118.   half_denominator = denominator / 2;
  119.   jobmag = mag;
  120.   fntdirveclen = min(MAXFNTDIR,dirveclen);
  121.   for (i = 0; i < fntdirveclen; i++) fntdirvec[i] = dirvec[i];
  122.   ndvifonts = 0;
  123.   nqmsfonts = 0;
  124.   timestamp = 0;
  125.   qms = printer;
  126.   filter_name = pgmnam;
  127.   if (options & F_INIT_LANDSCAPE) job_orientation = 'L';
  128.   else job_orientation = 'P';
  129.   if (options & F_INIT_QMS800) printer_orientation = 'P';
  130.   else printer_orientation = 'L';
  131. }
  132.  
  133. /* Called at the end of the driver program. */
  134. f_term()
  135. {
  136. }
  137.  
  138. struct qmsfont *
  139. find_qmsfont(area,name,texmag,s)
  140.      char *area,*name;
  141.      long texmag,s;
  142. {
  143.   char fname[MAXNAMLEN],nname[128];
  144.   int i,nmag;
  145.   int mag = (texmag * 3 + 1) / 2;
  146.   struct qmsfont *fnt;
  147.  
  148.   /* try to find a font file */
  149.   if (!findfile(fntdirvec,fntdirveclen,area,name,mag,fname,nname,&nmag))
  150.     croak("no font %s.%d",name,texmag);
  151.   
  152.   /* make a new qms font */
  153.   if (nqmsfonts >= MAXQMSFONTS) croak("too many qms fonts");
  154.   if (!(qmsfonts[nqmsfonts++] = fnt =
  155.     (struct qmsfont *) malloc(sizeof(struct qmsfont)))) 
  156.     croak("malloc %d",sizeof(struct qmsfont));
  157.   fnt->qf_mag = nmag;
  158.   fnt->qf_timestamp = 0;
  159.   fnt->qf_words_needed = 400;
  160.   fnt->qf_words_used = 0;
  161.   fnt->qf_qmsnumber = nqmsfonts + 1000;
  162.   sprintf(fnt->qf_qmsname,"%04.4d",fnt->qf_qmsnumber);
  163.   fnt->qf_maxheight = 0;
  164.   fnt->qf_s = s;
  165.   strcpy(fnt->qf_name,nname);
  166.   strcpy(fnt->qf_filename,fname);
  167.   fnt->qf_info = QF_FILE;
  168.   return(fnt);
  169. }
  170.  
  171. getfontfromfile(fnt)
  172.      struct qmsfont *fnt;
  173. {
  174.   char fname[MAXNAMLEN];
  175.   FILE *f;
  176.   int i;
  177.  
  178.   sprintf(fname,"%sr",fnt->qf_filename);
  179.   if (USEROTPXL && job_orientation != printer_orientation) {
  180.     if (!access(fname,4)) readpxlfile(fnt,fname,1);
  181.     else {
  182.       readpxlfile(fnt,fnt->qf_filename,0);
  183.       if (f = fopen(fname,"w")) {
  184.     fclose(f);
  185.     for (i = 0; i < MAXCHARS; i++) rotate(&(fnt->qf_char[i]),fnt);
  186.     writepxlfile(fnt,fname);
  187.       }
  188.     }
  189.   } else readpxlfile(fnt,fnt->qf_filename,0);
  190.   fnt->qf_info &= ~QF_FILE;
  191. }
  192.  
  193. writepxlfile(fnt,fname)
  194.      struct qmsfont *fnt;
  195.      char *fname;
  196. {
  197.   FILE *f;
  198.   long glyphaddrs[MAXCHARS],pxl_dir_ptr;
  199.  
  200.   if (!(f = fopen(fname,"w"))) croak("can't open %s to write",fname);
  201.   put4(1001,f);
  202.   writeglyphs(fnt,f,glyphaddrs);
  203.   pxl_dir_ptr = ftell(f) / 4;
  204.   writepxldir(fnt,f,glyphaddrs);
  205.   put4(fnt->qf_pxl_checksum,f);
  206.   put4(fnt->qf_pxl_mag_val,f);
  207.   put4(fnt->qf_pxl_design_size,f);
  208.   put4(pxl_dir_ptr,f);
  209.   put4(1001,f);
  210.   fclose(f);
  211. }
  212.  
  213. writepxldir(fnt,f,glyphaddrs)
  214.      struct qmsfont *fnt;
  215.      FILE *f;
  216.      long glyphaddrs[];
  217. {
  218.   int i;
  219.   struct qmschar *c;
  220.  
  221.   for (i = 0; i < MAXCHARS; i++) {
  222.     c = &(fnt->qf_char[i]);
  223.     put2(c->qc_width,f);
  224.     put2(c->qc_height,f);
  225.     put2(c->qc_xoffset,f);
  226.     put2(c->qc_yoffset,f);
  227.     put4(glyphaddrs[i],f);
  228.     put4(c->qc_pxlwidth,f);
  229.   }
  230. }
  231.  
  232. writeglyphs(fnt,f,glyphaddrs)
  233.      struct qmsfont *fnt;
  234.      FILE *f;
  235.      long glyphaddrs[];
  236. {
  237.   register int j;
  238.   int i,fbw,bw,row;
  239.   struct qmschar *c;
  240.   register unsigned char *p;
  241.  
  242.   for (i = 0; i < MAXCHARS; i++) {
  243.     c = &(fnt->qf_char[i]);
  244.     if (c->qc_glyph.p) {
  245.       glyphaddrs[i] = ftell(f) / 4;
  246.       /* Write out this glyph to the PXL file */
  247.       p = c->qc_glyph.p;
  248.       bw = (c->qc_width + 7) / 8;
  249.       fbw = ((c->qc_width + 31) / 32) * 4;
  250.       for (row = 0; row < c->qc_height; row++) {
  251.     for (j = 0; j < bw; j++) putc(*p++,f);
  252.     for (j = bw; j < fbw; j++) putc(0,f);
  253.       }
  254.     } else glyphaddrs[i] = 0;
  255.   }
  256. }
  257.  
  258. int char_words_needed(c)
  259.      struct qmschar *c;
  260. {
  261.   if (c->qc_info & QC_ROTATED)
  262.     return(((c->qc_width + 15) / 16) * c->qc_height);
  263.   else
  264.     return(((c->qc_height + 15) / 16) * c->qc_width);
  265. }
  266.  
  267. int font_blocks_used(fnt)
  268.      struct qmsfont *fnt;
  269. {
  270.   return((fnt->qf_words_used + 511) / 512);
  271. }
  272.  
  273. int font_blocks_needed(fnt)
  274.      struct qmsfont *fnt;
  275. {
  276.   return((fnt->qf_words_needed + fnt->qf_words_used + 511) / 512
  277.      - font_blocks_used(fnt));
  278. }
  279.  
  280. /* Define a font.
  281.  * Can be called more than once for the same font.
  282.  */
  283. f_define_font(num,options,area,name,texmag,s,tfmchecksum)
  284. char *area,*name;
  285. unsigned long num,options,texmag,s,tfmchecksum;
  286. {
  287.   int i;
  288.  
  289.   /* check to see if font is already defined */
  290.   for(i = 0; i < ndvifonts ; i++) if (dvifonts[i].df_num == num) return;
  291.  
  292.   /* Does this make too many fonts defined? */
  293.   if (ndvifonts >= MAXDVIFONTS) croak("too many dvi fonts");
  294.   dvifonts[ndvifonts].df_num = num;
  295.   dvifonts[ndvifonts++].df_qmsfont = find_qmsfont(area,name,texmag,s);
  296. }
  297.  
  298. struct qmsfont *
  299. find_dvi_font(fontnum)
  300.      unsigned long fontnum;
  301. {
  302.   register int i;
  303.  
  304.   /* scan through the dvi font list. */
  305.   for(i = 0; i < ndvifonts ; i++)
  306.     if (dvifonts[i].df_num == fontnum) {
  307.       dvifonts[i].df_qmsfont->qf_timestamp = timestamp++;
  308.       return(dvifonts[i].df_qmsfont);
  309.     }
  310.   croak("no dvi font %d defined",fontnum);
  311. }
  312.  
  313. /* Set a font as the current font.
  314.  */
  315. f_use_font(fontnum,font_space)
  316. unsigned long fontnum;
  317. long *font_space;
  318. {
  319.   curfnt = find_dvi_font(fontnum);
  320.   if (curfnt->qf_info & QF_FILE) getfontfromfile(curfnt);
  321.   /* Make sure that it's loaded in the printer */
  322.   if (!(curfnt->qf_info & QF_LOADED)
  323.       || (curfnt->qf_info & QF_RELOAD))
  324.     download_font(curfnt);
  325.   /* Start using it */
  326.   fprintf(qms,SELECTFONT,curfnt->qf_qmsnumber);
  327.   *font_space = curfnt->qf_s / 6;
  328. }
  329.  
  330. /* Hints as to what fonts are to be used.
  331.  * This is called once per page to give fonts module hints as what fonts
  332.  * and characters in those fonts are going to be used on this page.
  333.  */
  334. f_newpage(fontvec,charvec,veclen)
  335.      unsigned long fontvec[];
  336.      unsigned long charvec[][4];
  337.      int veclen;
  338. {
  339.   struct qmschar *c;
  340.   register int i,j;
  341.   struct qmsfont *f;
  342.  
  343.   for (i = 0; i < veclen; i++) {
  344.     f = find_dvi_font(fontvec[i]);
  345.     if (f->qf_info & QF_FILE) getfontfromfile(f);
  346.     if (!(f->qf_info & QF_LOADED)) {
  347.       f->qf_words_used = 0;
  348.       f->qf_words_needed = 400;
  349.     }
  350.     for (j = 0; j < MAXCHARS; j++) 
  351.       if (charvec[i][j/32] & (1 << (j % 32))) {
  352.     c = &(f->qf_char[j]);
  353.     c->qc_info |= QC_NEEDED;
  354.     if (!(c->qc_info & QC_LOADED)) {
  355.       f->qf_info |= QF_RELOAD;
  356.       f->qf_words_needed += char_words_needed(c);
  357.     }
  358.       } else f->qf_char[j].qc_info &= ~QC_NEEDED;
  359.   }
  360. }
  361.  
  362. clear(p,n)
  363.      char *p;
  364.      int n;
  365. {
  366.   while (n-- > 0) *p++ = 0;
  367. }
  368.  
  369. rotate(c,fnt)
  370.      struct qmschar *c;
  371.      struct qmsfont *fnt;
  372. {
  373.   unsigned char *oldglyph = c->qc_glyph.p;
  374.   unsigned int width = (unsigned int)c->qc_width;
  375.   unsigned int  height = (unsigned int)c->qc_height;
  376.   int newbyteswide = (c->qc_height + 7) / 8;
  377.   int oldbyteswide = (c->qc_width + 7) / 8;
  378.   unsigned char *newglyph,*putbyte;
  379.   int column;
  380.   int row = -1;            /* Start row at 0 when incremented */
  381.   int mask;
  382.   int i, j;
  383.   int times;
  384.   int extractbyte;
  385.  
  386.   if (!(c->qc_info & QC_NOGLYPH)) {
  387.     if (!(newglyph = malloc(newbyteswide * width)))
  388.       croak("malloc %d",newbyteswide * width);
  389.     clear(newglyph, newbyteswide * width);
  390.  
  391.     for (i = 0; i < oldbyteswide * height; i++) {
  392.       extractbyte = *(oldglyph + i);
  393.       if (i % oldbyteswide == 0) row++;
  394.       times = (i + 1) % oldbyteswide ? 8 : (width + 7) % 8 + 1;
  395.       for (j = 0, mask = 0x80; j < times; j++, mask >>= 1) {
  396.     column = (((i % oldbyteswide) == 0) && (j == 0)) ? 0 : (column + 1);
  397.     if (mask & extractbyte) {
  398.       putbyte = newglyph + column * newbyteswide +
  399.         (int)((height - (row + 1)) / 8);
  400.       *putbyte |= 1 << 7 - ((height + 7) - row) % 8;
  401.     }
  402.       }
  403.     }
  404.     free(oldglyph);
  405.     c->qc_glyph.p = newglyph;
  406.   }
  407.   c->qc_info |= QC_ROTATED;
  408.   i = c->qc_width;
  409.   c->qc_width = c->qc_height;
  410.   c->qc_height = i;
  411.   i = c->qc_xoffset;
  412.   c->qc_xoffset = c->qc_width - c->qc_yoffset - fnt->qf_maxheight;
  413.   c->qc_yoffset = i;
  414. }
  415.  
  416. /* Load a font into the qms.
  417.  */
  418. download_font(fnt)
  419.      struct qmsfont *fnt;
  420. {
  421.   register int i;
  422.  
  423.   if (font_blocks_needed(fnt) > freeblocks)
  424.     qmsfree(font_blocks_needed(fnt));
  425.   freeblocks -= font_blocks_needed(fnt);
  426.   fnt->qf_words_used += fnt->qf_words_needed;
  427.   fnt->qf_words_needed = 0;
  428.   if (fnt->qf_info & QF_LOADED) {
  429.     fprintf(qms,
  430.         ADDTOFONT,
  431.         fnt->qf_qmsnumber,job_orientation,
  432.         1,fnt->qf_qmsname,fnt->qf_maxheight);
  433.   } else {
  434.     fprintf(qms,
  435.         DEFINEFONT,
  436.         fnt->qf_qmsnumber,job_orientation,
  437.         1,fnt->qf_qmsname,fnt->qf_maxheight);
  438.   }
  439.   for (i = 0; i < MAXCHARS; i++)
  440.     if ((fnt->qf_char[i].qc_info & QC_NEEDED)
  441.     && !(fnt->qf_char[i].qc_info & QC_LOADED))
  442.       load_char(i,fnt);
  443.   fprintf(qms,ENDDEF);
  444.   fnt->qf_info |= QF_LOADED;
  445.   fnt->qf_info &= ~QF_RELOAD;
  446. }
  447.  
  448. load_char(ch,fnt)
  449.      unsigned long ch;
  450.      struct qmsfont *fnt;
  451. {
  452.   register unsigned char *bp;
  453.   register int bytes;
  454.   struct qmschar *c = &(fnt->qf_char[ch]);
  455.   int row,bw,bo;
  456.  
  457.   if (job_orientation != printer_orientation
  458.       && !(c->qc_info & QC_ROTATED)) rotate(c,fnt);
  459.   bp = c->qc_glyph.p;
  460.   fprintf(qms,DEFINECHAR,hex[(ch >> 4) & 017],hex[ch & 017],
  461.       c->qc_qmswidth,c->qc_height,c->qc_width,
  462.       (c->qc_yoffset < 0) ? '+' : '-',abs(c->qc_yoffset),
  463.       (c->qc_xoffset < 0) ? '+' : '-',abs(c->qc_xoffset));
  464.   bw = (c->qc_width + 7) / 8;
  465.   bo = ((c->qc_width + 15) / 16) * 2;
  466.   for (row = 0; row < c->qc_height; row++) {
  467.     for (bytes = 0; bytes < bw; bytes++) putc(*bp++,qms);
  468.     if (bw != bo) putc(0,qms);
  469.   }
  470.   c->qc_info |= QC_LOADED;
  471. }
  472.  
  473. int readpxlfile(fnt,fname,rotated)
  474.      struct qmsfont *fnt;
  475.      char *fname;
  476.      int rotated;
  477. {
  478.   long pxl_id,pxl_dir_ptr;
  479.   FILE *f;
  480.  
  481.   if (!(f = fopen(fname,"r"))) croak("no pxl file %s",fname);
  482.   if ((pxl_id = sget4(f)) != 1001)
  483.     croak("%d bad initial pxl ID; %s doesn't look like a pxl file",
  484.       pxl_id, fnt->qf_filename);
  485.  
  486.   /* Read the last 5 longs from the pxl file */
  487.   (void) fseek(f, (long)(-5*4), 2);
  488.   fnt->qf_pxl_checksum = sget4(f);
  489.   fnt->qf_pxl_mag_val = sget4(f);
  490.   fnt->qf_pxl_design_size = sget4(f);
  491.   pxl_dir_ptr = sget4(f);
  492.   if ((pxl_id = sget4(f)) != 1001)
  493.     croak("%d bad final pxl ID; %s doesn't look like a pxl file",
  494.       pxl_id, fnt->qf_filename);
  495.   if (pxl_dir_ptr != ftell(f) / 4 - 517) 
  496.     croak("%s pxl dir ptr is %x, should be %x",
  497.       fnt->qf_filename, pxl_dir_ptr, ftell(f) / 4 - 517);
  498.   debug("pxl: checksum %d mag %d designsize %d dir %x\n",
  499.     fnt->qf_pxl_checksum,fnt->qf_pxl_mag_val,
  500.     fnt->qf_pxl_design_size,pxl_dir_ptr);
  501.  
  502.   /* Read the directory */
  503.   (void) fseek(f, pxl_dir_ptr * 4, 0);
  504.   getpxldir(fnt,f,rotated);
  505.   debug("     %s max_height=%d\n",fnt->qf_filename,fnt->qf_maxheight);
  506.  
  507.   /* Read in all the glyphs */
  508.   getglyphs(fnt,f);
  509.  
  510.   (void) fclose(f);
  511. }
  512.  
  513. getpxldir(fnt,f,rotated)
  514.      struct qmsfont *fnt;
  515.      FILE *f;
  516.      int rotated;
  517. {
  518.   int i;
  519.   struct qmschar *c;
  520.   double ds = ((double) fnt->qf_s) / ((double) (1 << 20));
  521.  
  522.   fnt->qf_maxheight = 0;
  523.   for (i = 0; i < MAXCHARS; i++) {
  524.     c = &(fnt->qf_char[i]);
  525.     c->qc_width = sget2(f);
  526.     c->qc_height = sget2(f);
  527.     c->qc_xoffset = sget2(f);
  528.     c->qc_yoffset = sget2(f);
  529.     c->qc_glyph.l = get4(f);
  530.     c->qc_pxlwidth = sget4(f);
  531.     c->qc_texwidth = (long) (((double) c->qc_pxlwidth) * ds);
  532.     c->qc_qmswidth = 
  533.       (c->qc_texwidth * numerator + half_denominator) / denominator;
  534.     if (rotated) {
  535.       c->qc_info = QC_NOGLYPH | QC_ROTATED;
  536.       fnt->qf_maxheight = max(fnt->qf_maxheight,c->qc_width);
  537.     } else {
  538.       c->qc_info = QC_NOGLYPH;
  539.       fnt->qf_maxheight = max(fnt->qf_maxheight,c->qc_height);
  540.     }
  541.   }
  542. }
  543.  
  544. getglyphs(fnt,f)
  545.      struct qmsfont *fnt;
  546.      FILE *f;
  547. {
  548.   register int j,row;
  549.   register unsigned char *p;
  550.   int i,fbw,bw;
  551.   struct qmschar *c;
  552.  
  553.   for (i = 0; i < MAXCHARS; i++) {
  554.     c = &(fnt->qf_char[i]);
  555.     if (c->qc_glyph.l) {
  556.       (void) fseek(f, c->qc_glyph.l * 4, 0);
  557.       fbw = ((c->qc_width + 31) / 32) * 4;
  558.       bw = (c->qc_width + 7) / 8;
  559.       if (!(p = malloc(bw * c->qc_height)))
  560.     croak("malloc %d",bw * c->qc_height);
  561.       c->qc_glyph.p = p;
  562.       for (row = 0; row < c->qc_height; row++) {
  563.     for (j = 0; j < bw; j++) *p++ = getc(f);
  564.     for (j = bw; j < fbw; j++) (void) getc(f);
  565.       }
  566.       c->qc_info &= ~QC_NOGLYPH;
  567.     }
  568.   }
  569. }
  570.  
  571. /* Make sure that the font info for this character is loaded.
  572.  * Characters are incrementally loaded into the printer.
  573.  * This procedure is called for every character so it must be fast.
  574.  */
  575. f_use_char(ch,texwidth,devwidth)
  576. unsigned long ch;
  577. long *texwidth,*devwidth;
  578. {
  579.   register struct qmschar *c = &(curfnt->qf_char[ch]);
  580.  
  581.   *texwidth = c->qc_texwidth;
  582.   *devwidth = c->qc_qmswidth;
  583. }
  584.  
  585.  
  586. /* free blocks by deleting font(s) using LRU strategy */
  587. int qmsfree(blocks)
  588.      int blocks;
  589. {
  590.   int i,oldtime;
  591.   struct qmsfont *oldfont;  
  592.  
  593.   while (blocks > freeblocks) {
  594.     oldfont = NULL;
  595.     oldtime = timestamp;
  596.     for (i = 0; i < nqmsfonts; i++)
  597.       if ((qmsfonts[i]->qf_info & QF_LOADED)
  598.       && (qmsfonts[i]->qf_timestamp < oldtime)) {
  599.     oldfont = qmsfonts[i];
  600.     oldtime = oldfont->qf_timestamp;
  601.       }
  602.     if (!oldfont) croak("qmsfree bug");
  603.     fprintf(qms,DELETEFONT,oldfont->qf_qmsnumber,job_orientation);
  604.     freeblocks += font_blocks_used(oldfont);
  605.     oldfont->qf_info &= ~QF_LOADED;
  606.     oldfont->qf_words_needed = 400;
  607.     oldfont->qf_words_used = 0;
  608.     for (i = 0; i < MAXCHARS; i++) {
  609.       oldfont->qf_char[i].qc_info &= ~QC_LOADED;
  610.       if (oldfont->qf_char[i].qc_info & QC_NEEDED)
  611.     oldfont->qf_words_needed += char_words_needed(&(oldfont->qf_char[i]));
  612.     }
  613.   }
  614. }
  615.